<template>
  <div class="goods-sku">
    <dl v-for="spec in goods.specs" :key="spec.id">
      <dt>{{ spec.name }}</dt>
      <dd>
        <template v-for="btn in spec.values" :key="btn.name">
          <img
            :class="{ selected: btn.selected, disabled: btn.disabled }"
            @click="changeSku(btn, spec)"
            v-if="btn.picture"
            :src="btn.picture"
            alt=""
          />
          <span
            :class="{ selected: btn.selected, disabled: btn.disabled }"
            @click="changeSku(btn, spec)"
            v-else
            >{{ btn.name }}</span
          >
        </template>
      </dd>
    </dl>
  </div>
</template>
<script>
import bwPowerSet from '@/vendor/power-set'
// 演示一下 bwPowerSet 的使用
// console.log(bwPowerSet(['蓝色', '10cm', '中国']))
// 封装 一个方法  根据 goods.skus  整理路径字典
const spliter = '☆'
const getPathMap = (skus) => {
  const pathMap = {}
  // 1、过滤出有库存的 有效sku 即 inventory （库存） 不为0的
  skus.filter(sku => sku.inventory > 0)
    // filter 返回的还是数组，链式调用循环
    .forEach(sku => {
      // 2、找到符合条件的sku 可以去进行处理
      const arr = sku.specs.map(item => item.valueName)
      // console.log('AmapA', arr)
      // 3、使用算法求子集
      const sets = bwPowerSet(arr)
      // console.log('AsetA', sets)
      // 4、整理自己，组合字典=> {}
      sets.forEach(set => {
        // 用个五角星 拼接就是为了 让同学们看清条件,下面进行拼接.把子级数组转换成字符串,为什么转？因为字典是{}，对象不能key组合
        const key = set.join(spliter)
        // console.log('key', key)
        // [sku.id] 相当于 先 pathMap[key] = []  然后 pathMap[key].push(sku.id)
        // 当没有pathMap对象没有这个key的时候 新建一个属性  key: [id]  如果有这个key值了 直接push(id)
        // 详解：里面没有这个黑色key时，就把key的id传进去。再来一个黑色key时，就把这个id也传进来
        if (pathMap[key]) {
          pathMap[key].push(sku.id)
        } else {
          // pathMap={}是个空对象‘
          // pathMap['黑色']=[1] ===>{'黑色'：[sku.id]}
          pathMap[key] = [sku.id]
        }
      })
    })
  return pathMap
}
// 想要获取选中规格的名字
// 得到的结果得保证顺序   [undefined,undefined,undefined][
// ['黑色',undefined,undefined]
// [undefined,'30cm',undefined]
// [undefined,undefined,'中国']
const getSelectedSpec = (specs) => {
  const arr = []
  specs.forEach((spec, index) => {
    // spec 是每一行
    // 一行按钮里  只有一个选中的
    const btn = spec.values.find(obj => obj.selected === true)
    // console.log('asdsadasd', btn)

    if (btn) {
      // 选中了， 将选中的名字 存到数组的对应 项中 （spec行）
      arr[index] = btn.name
    } else {
      // 没有找到  这一行没选中， 存个undefined
      arr[index] = undefined
    }
  })
  return arr
}
/*
  核心逻辑：遍历 按钮，然后看在不在字典中，
  初始化的时候，判断单个按钮就行，点击按钮之后，需要组合起来判断在不在字典里
*/

const updateDisabledStatus = (specs, pathMap) => {
  // 引用类型备份，最好深拷贝一下，用JSON.stringify（）
  const selectedJSON = JSON.stringify(getSelectedSpec(specs))
  // console.log('备份初始化选中数据', selectedJSON) // [null,null,null] 刷新页面 啥也没有
  // 遍历之后获取每一行按钮
  specs.forEach((spec, i) => {
    // 遍历获取到 每一个按钮， 如果没有选中的，就是判断单个按钮在不在字典里
    // 一但有选中的，就需要 把 将要选中的项 和已选中的进行  组合
    // spec.values  是每一行按钮
    spec.values.forEach(btn => {
      // 每一次 打印一下btn
      // console.log(btn, btn.name) //btn.name 是每一按钮的 的名字
      const selectedArr = JSON.parse(selectedJSON)
      // 赋值 的是下一次 可能点击的按钮，一开始是[undefined, '20cm', '中国'] 下一次点击的是['黑色', '20cm', '中国'] 或者[undefined, '30cm', '中国']
      // i  是第几行
      selectedArr[i] = btn.name // 给每一行的每一个按钮 赋值名字
      // 获取的全部可切换的选项
      // console.log('selectedArr是什么', selectedArr) // selectedArr 是之前备份的 sku 的名字,
      // 数据筛选一下，筛选出来部位u'nde'fined的名字在拼接 简写（v=v）===（v=>{ if (v) {return v}}）
      const key = selectedArr.filter(v => v).join(spliter)
      // 处理之后的数组join 拼接成 蓝色☆ 中国
      // console.log('key是什么', key) // key 是点击之后的拼接成的skuid

      // 在字典里就不禁用,  不在字典里就禁用
      if (pathMap[key]) {
        btn.disabled = false
      } else {
        btn.disabled = true
      }
      // if (pathMap[btn.name]) {
      //   btn.disabled = false
      // } else {
      //   btn.disabled = true
      // }
    })
  })
}
// 初始化选中状态
const initDefaultStatus = (goods, skuId) => {
  // 1 从skus 中根据skuId  找到选中项
  const sku = goods.skus.find(item => item.id === skuId)
  // 2、 需要控制按钮的高亮,用if判断做一个健全  鉴权
  if (sku.specs) {
    goods.specs.forEach((spec, i) => {
      spec.values.forEach(btn => {
        console.log(sku)
        btn.selected = btn.name === sku.specs[i].valueName
      })
    })
  }
}

export default {
  name: 'GoodsSku',
  props: {
    goods: {
      type: Object,
      default: () => {
        return {
          specs: [],
          skus: []
        }
      }
      // default: () => ({
      //   specs: [],
      //   skus: []
      // })
    },
    skuId: {
      type: String,
      default: ''
    }
  },
  setup (props, context) {
    // 进入页面如果传入了skuId  ,默认按照skuId进行高亮也就是 selected给个true
    if (props.skuId) {
      initDefaultStatus(props.goods, props.skuId)
    }
    // 获取路径字典

    const pathMap = getPathMap(props.goods.skus)
    console.log('pathMap', pathMap)
    // 初始化的时候更新一下按钮状态
    updateDisabledStatus(props.goods.specs, pathMap)
    const changeSku = (btn, spec) => {
      // 做个健全  如果不可点击 直接返回
      if (btn.disabled) return
      // 我们给选中的一个添加选中属性
      if (btn.selected) {
        btn.selected = false
      } else {
        // 只需要我自己防火，其他都给灭了，先取消所有，在选中自己
        spec.values.forEach(item => {
          item.selected = false
        })
        btn.selected = true
      }
      // 点击的时候也需要更新按钮状态
      updateDisabledStatus(props.goods.specs, pathMap)
      // 按顺序获取选中按钮 ['a' , 'b', undefinde]
      const selectedArr = getSelectedSpec(props.goods.specs).filter(v => v)
      console.log(selectedArr)
      if (selectedArr.length === props.goods.specs.length) {
        const skuId = (pathMap[selectedArr.join(spliter)][0])
        const sku = props.goods.skus.find(sku => sku.id === skuId)
        console.log('sku出来了', sku)
        context.emit('change', {
          skuId: sku.id,
          price: sku.price,
          oldPrice: sku.oldPrice,
          inventory: sku.inventory,
          specsText: sku.specs.reduce((str, item) => `${str} ${item.name}：${item.valueName}`, '').trim('')
        })
      } else {
        // 有没选中的
        context.emit('change', {})
      }
    }
    return {
      changeSku,
      pathMap
    }
  }
}
</script>
<style scoped lang="less">
.sku-state-mixin () {
  border: 1px solid #e4e4e4;
  margin-right: 10px;
  cursor: pointer;
  &.selected {
    border-color: @xtxColor;
  }
  &.disabled {
    opacity: 0.6;
    border-style: dashed;
    cursor: not-allowed;
  }
}
.goods-sku {
  padding-left: 10px;
  padding-top: 20px;
  dl {
    display: flex;
    padding-bottom: 20px;
    align-items: center;
    dt {
      width: 50px;
      color: #999;
    }
    dd {
      flex: 1;
      color: #666;
      > img {
        width: 50px;
        height: 50px;
        .sku-state-mixin ();
      }
      > span {
        display: inline-block;
        height: 30px;
        line-height: 28px;
        padding: 0 20px;
        .sku-state-mixin ();
      }
    }
  }
}
</style>
